From fbaf0773bbad202d4dec98f20ba97047ffe71151 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 11 Jun 2007 10:21:11 +0100 Subject: [PATCH] xend: Make device detach wait for detach to complete. *-detach will wait till device is detached or time'ed out. XendConfig will be updated, if detached. Signed-off-by: Max Zhen --- tools/python/xen/xend/XendConfig.py | 15 ++++++ tools/python/xen/xend/XendDomainInfo.py | 19 +++++++- tools/python/xen/xend/server/DevController.py | 46 +++++++++++++++++-- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 397fc437e8..5ca3233709 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -1268,6 +1268,21 @@ class XendConfig(dict): return False + def device_remove(self, dev_uuid): + """Remove an existing device referred by dev_uuid. + """ + + if dev_uuid in self['devices']: + dev_config = self['devices'].get(dev_uuid) + dev_type = dev_config[0] + + del self['devices'][dev_uuid] + # Remove dev references for certain device types (see device_add) + if dev_type in ('vif', 'vbd', 'vtpm'): + param = '%s_refs' % dev_type + if param in self: + if dev_uuid in self[param]: + self[param].remove(dev_uuid) def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None): """Get Device SXPR by either giving the device UUID or (type, config). diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 39d07b3645..4668f918c8 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -557,7 +557,23 @@ class XendDomainInfo: return None log.debug("dev = %s", dev) - return self.getDeviceController(deviceClass).destroyDevice(dev, force) + + dev_control = self.getDeviceController(deviceClass) + dev_uuid = dev_control.readBackend(dev, 'uuid') + + ret = None + + try: + ret = dev_control.destroyDevice(dev, force) + except EnvironmentError: + # We failed to detach the device + raise VmError("Failed to detach device %d" % dev) + + # update XendConfig + if dev_uuid: + self.info.device_remove(dev_uuid) + + return ret def getDeviceSxprs(self, deviceClass): if self._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED): @@ -571,7 +587,6 @@ class XendDomainInfo: dev_num += 1 return sxprs - def setMemoryTarget(self, target): """Set the memory target of this domain. @param target: In MiB. diff --git a/tools/python/xen/xend/server/DevController.py b/tools/python/xen/xend/server/DevController.py index c43ed2681b..faba7bf400 100644 --- a/tools/python/xen/xend/server/DevController.py +++ b/tools/python/xen/xend/server/DevController.py @@ -29,6 +29,7 @@ from xen.xend.xenstore.xswatch import xswatch import os DEVICE_CREATE_TIMEOUT = 100 +DEVICE_DESTROY_TIMEOUT = 10 HOTPLUG_STATUS_NODE = "hotplug-status" HOTPLUG_ERROR_NODE = "hotplug-error" HOTPLUG_STATUS_ERROR = "error" @@ -211,17 +212,34 @@ class DevController: devid = int(devid) + frontpath = self.frontendPath(devid) + if frontpath: + backpath = xstransact.Read(frontpath, "backend") + # Modify online status /before/ updating state (latter is watched by # drivers, so this ordering avoids a race). self.writeBackend(devid, 'online', "0") self.writeBackend(devid, 'state', str(xenbusState['Closing'])) if force: - frontpath = self.frontendPath(devid) - backpath = xstransact.Read(frontpath, "backend") if backpath: xstransact.Remove(backpath) - xstransact.Remove(frontpath) + if frontpath: + xstransact.Remove(frontpath) + return + + # Wait till both frontpath and backpath are removed from + # xenstore, or timed out + if frontpath: + status = self.waitUntilDestroyed(frontpath) + if status == Timeout: + # Exception will be caught by destroyDevice in XendDomainInfo.py + raise EnvironmentError + if backpath: + status = self.waitUntilDestroyed(backpath) + if status == Timeout: + # Exception will be caught by destroyDevice in XendDomainInfo.py + raise EnvironmentError self.vm._removeVm("device/%s/%d" % (self.deviceClass, devid)) @@ -508,6 +526,16 @@ class DevController: return (Missing, None) + def waitUntilDestroyed(self, path): + ev = Event() + result = { 'path': path, 'status': Timeout } + + xswatch(path, destroyCallback, ev, result) + + ev.wait(DEVICE_DESTROY_TIMEOUT) + return result['status'] + + def backendPath(self, backdom, devid): """Construct backend path given the backend domain and device id. @@ -537,6 +565,18 @@ class DevController: self.deviceClass) +def destroyCallback(devPath, ev, result): + log.debug("destroyCallback %s.", devPath) + + list = xstransact.List(result['path']) + if list: + return 1 + + result['status'] = Missing + ev.set() + log.debug("destroyCallback %s is destroyed", result['path']) + return 0 + def hotplugStatusCallback(statusPath, ev, result): log.debug("hotplugStatusCallback %s.", statusPath) -- 2.30.2